unit EuConfig;

interface

uses
  Classes, SysUtils, Math;

type

  TEuConfigReadEvent = procedure(Sender: TObject;
    const Ident, DefValue: string; var Value: string) of object;

  TEuConfigWriteEvent = procedure(Sender: TObject;
    const Ident, Value: string) of object;

  TEuConfig = class(TComponent)
  private
    FOnRead: TEuConfigReadEvent;
    FOnWrite: TEuConfigWriteEvent;
  protected
    procedure DoRead(const Ident, DefValue: string; var Value: string); virtual;
    procedure DoWrite(const Ident, Value: string); virtual;
  public
    function ReadString(const Ident, DefValue: string): string; overload;
    function ReadString(const Ident: string): string; overload;

    function ReadInteger(const Ident: string;
      const DefValue: integer): integer; overload;
    function ReadInteger(const Ident: string;
      const DefValue, MinValue, MaxValue: integer): integer; overload;
    function ReadInteger(const Ident: string): integer; overload;

    function ReadFloat(const Ident: string;
      const DefValue: Extended): Extended; overload;
    function ReadFloat(const Ident: string;
      const DefValue, MinValue, MaxValue: Extended): Extended; overload;
    function ReadFloat(const Ident: string): Extended; overload;

    function ReadDec(const Ident: string;
      const DefValue: Extended; const Decimals: integer): Extended; overload;
    function ReadDec(const Ident: string;
      DefValue, MinValue, MaxValue: Extended;
      const Decimals: integer): Extended; overload;
    function ReadDec(const Ident: string;
      const Decimals: integer): Extended; overload;

    function ReadDateTime(const Ident: string;
      const DefValue: TDateTime): TDateTime; overload;
    function ReadDateTime(const Ident: string;
      const DefValue, MinValue, MaxValue: TDateTime): TDateTime; overload;
    function ReadDateTime(const Ident: string): TDateTime; overload;

    function ReadDate(const Ident: string;
      const DefValue: TDateTime): TDateTime; overload;
    function ReadDate(const Ident: string;
      DefValue, MinValue, MaxValue: TDateTime): TDateTime; overload;
    function ReadDate(const Ident: string): TDateTime; overload;

    function ReadTime(const Ident: string;
      DefValue: TDateTime): TDateTime; overload;
    function ReadTime(const Ident: string;
      DefValue, MinValue, MaxValue: TDateTime): TDateTime; overload;
    function ReadTime(const Ident: string): TDateTime; overload;

    function ReadBool(const Ident: string;
      const DefValue: boolean): boolean; overload;
    function ReadBool(const Ident: string): boolean; overload;

    procedure WriteString(const Ident, Value: string);
    procedure WriteInteger(const Ident: string; const Value: integer);
    procedure WriteFloat(const Ident: string; const Value: Extended);
    procedure WriteDec(const Ident: string; const Value: Extended;
      const Decimals: integer);
    procedure WriteDateTime(const Ident: string; const Value: TDateTime);
    procedure WriteDate(const Ident: string; const Value: TDateTime);
    procedure WriteTime(const Ident: string; const Value: TDateTime);
    procedure WriteBool(const Ident: string; const Value: boolean);
  published
    property OnRead: TEuConfigReadEvent read FOnRead write FOnRead;
    property OnWrite: TEuConfigWriteEvent read FOnWrite write FOnWrite;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('EuMisc', [TEuConfig]);
end;

function TruncDec(const Value: Extended; const Decimals: integer): Extended;
var
  Factor: Extended;
begin
  Factor := IntPower(10, Decimals);
  Result := Trunc(Value * Factor) / Factor;
end;

{ Private }

procedure TEuConfig.DoRead(const Ident, DefValue: string; var Value: string);
begin
  if Assigned(FOnRead) then
    FOnRead(Self, Ident, DefValue, Value);
end;

procedure TEuConfig.DoWrite(const Ident, Value: string);
begin
  if Assigned(FOnWrite) then
    FOnWrite(Self, Ident, Value);
end;

{ Public }

function TEuConfig.ReadString(const Ident, DefValue: string): string;
begin
  DoRead(Ident, DefValue, Result);
end;

function TEuConfig.ReadString(const Ident: string): string;
begin
  Result := ReadString(Ident, '');
end;

function TEuConfig.ReadInteger(const Ident: string;
  const DefValue: integer): integer;
var
  S: string;
begin
  DoRead(Ident, IntToStr(DefValue), S);
  Result := StrToIntDef(S, DefValue);
end;

function TEuConfig.ReadInteger(const Ident: string;
  const DefValue, MinValue, MaxValue: integer): integer;
begin
  Result := ReadInteger(Ident, DefValue);
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadInteger(const Ident: string): integer;
begin
  Result := ReadInteger(Ident, 0);
end;

function TEuConfig.ReadFloat(const Ident: string;
  const DefValue: Extended): Extended;
var
  Sep: Char;
  S: string;
begin
  Sep := FormatSettings.DecimalSeparator;
  try
    FormatSettings.DecimalSeparator := '.';
    S := ReadString(Ident, FloatToStr(DefValue));
    Result := StrToFloatDef(S, DefValue);
  finally
    FormatSettings.DecimalSeparator := Sep;
  end;
end;

function TEuConfig.ReadFloat(const Ident: string;
  const DefValue, MinValue, MaxValue: Extended): Extended;
begin
  Result := ReadFloat(Ident, DefValue);
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadFloat(const Ident: string): Extended;
begin
  Result := ReadFloat(Ident, 0);
end;

function TEuConfig.ReadDec(const Ident: string;
  const DefValue: Extended; const Decimals: integer): Extended;
begin
  Result := ReadFloat(Ident, TruncDec(DefValue, Decimals));
end;

function TEuConfig.ReadDec(const Ident: string;
  DefValue, MinValue, MaxValue: Extended;
  const Decimals: integer): Extended;
begin
  DefValue := TruncDec(DefValue, Decimals);
  MinValue := TruncDec(MinValue, Decimals);
  MaxValue := TruncDec(MaxValue, Decimals);
  Result := ReadDec(Ident, DefValue, Decimals);
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadDec(const Ident: string;
  const Decimals: integer): Extended;
begin
  Result := ReadDec(Ident, 0, Decimals);
end;

function TEuConfig.ReadDateTime(const Ident: string;
  const DefValue: TDateTime): TDateTime;
var
  DateSep, TimeSep: Char;
  S: string;
begin
  DateSep := FormatSettings.DateSeparator;
  TimeSep := FormatSettings.TimeSeparator;
  try
    FormatSettings.DateSeparator := '/';
    FormatSettings.TimeSeparator := ':';
    S := ReadString(Ident, DateTimeToStr(DefValue));
    Result := StrToDateTimeDef(S, DefValue);
  finally
    FormatSettings.DateSeparator := DateSep;
    FormatSettings.TimeSeparator := TimeSep;
  end;
end;

function TEuConfig.ReadDateTime(const Ident: string;
  const DefValue, MinValue, MaxValue: TDateTime): TDateTime;
begin
  Result := ReadDateTime(Ident, DefValue);
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadDateTime(const Ident: string): TDateTime;
begin
  Result := ReadDateTime(Ident, 0);
end;

function TEuConfig.ReadDate(const Ident: string;
  const DefValue: TDateTime): TDateTime;
begin
  Result := Int(ReadDateTime(Ident, Int(DefValue)));
end;

function TEuConfig.ReadDate(const Ident: string;
  DefValue, MinValue, MaxValue: TDateTime): TDateTime;
begin
  DefValue := Int(DefValue);
  MinValue := Int(MinValue);
  MaxValue := Int(MaxValue);
  Result := Int(ReadDateTime(Ident, DefValue));
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadDate(const Ident: string): TDateTime;
begin
  Result := Int(ReadDateTime(Ident, 0));
end;

function TEuConfig.ReadTime(const Ident: string;
  DefValue: TDateTime): TDateTime;
begin
  Result := Frac(ReadDateTime(Ident, Frac(DefValue)));
end;

function TEuConfig.ReadTime(const Ident: string;
  DefValue, MinValue, MaxValue: TDateTime): TDateTime;
begin
  DefValue := Frac(DefValue);
  MinValue := Frac(MinValue);
  MaxValue := Frac(MaxValue);
  Result := Frac(ReadDateTime(Ident, DefValue));
  if (Result < MinValue) or (Result > MaxValue) then
  begin
    if (DefValue >= MinValue) and (DefValue <= MaxValue) then
      Result := DefValue
    else
      Result := MinValue;
  end;
end;

function TEuConfig.ReadTime(const Ident: string): TDateTime;
begin
  Result := ReadTime(Ident, 0);
end;

function TEuConfig.ReadBool(const Ident: string;
  const DefValue: boolean): boolean;
begin
  Result := Boolean(ReadInteger(Ident, Integer(DefValue)));
end;

function TEuConfig.ReadBool(const Ident: string): boolean;
begin
  Result := ReadBool(Ident, false);
end;

procedure TEuConfig.WriteString(const Ident, Value: string);
begin
  DoWrite(Ident, Value);
end;

procedure TEuConfig.WriteInteger(const Ident: string; const Value: integer);
begin
  WriteString(Ident, IntToStr(Value));
end;

procedure TEuConfig.WriteFloat(const Ident: string; const Value: Extended);
var
  Sep: Char;
begin
  Sep := FormatSettings.DecimalSeparator;
  try
    FormatSettings.DecimalSeparator := '.';
    WriteString(Ident, FloatToStr(Value));
  finally
    FormatSettings.DecimalSeparator := Sep;
  end;
end;

procedure TEuConfig.WriteDec(const Ident: string; const Value: Extended;
  const Decimals: integer);
begin
  WriteFloat(Ident, TruncDec(Value, Decimals));
end;

procedure TEuConfig.WriteDateTime(const Ident: string; const Value: TDateTime);
var
  DateSep, TimeSep: Char;
begin
  DateSep := FormatSettings.DateSeparator;
  TimeSep := FormatSettings.TimeSeparator;
  try
    FormatSettings.DateSeparator := '/';
    FormatSettings.TimeSeparator := ':';
    WriteString(Ident, DateTimeToStr(Value));
  finally
    FormatSettings.DateSeparator := DateSep;
    FormatSettings.TimeSeparator := TimeSep;
  end;
end;

procedure TEuConfig.WriteDate(const Ident: string; const Value: TDateTime);
begin
  WriteDateTime(Ident, Int(Value));
end;

procedure TEuConfig.WriteTime(const Ident: string; const Value: TDateTime);
begin
  WriteDateTime(Ident, Frac(Value));
end;

procedure TEuConfig.WriteBool(const Ident: string; const Value: boolean);
begin
  WriteInteger(Ident, Integer(Value));
end;

end.

